package com.zrkizzy.thread.practice;

import java.util.concurrent.ArrayBlockingQueue;

/**
 * 生产者-消费者模型练习题
 * <p>
 * <b>任务：</b>使用多线程编写一个简单的生产者-消费者模型。<br />
 * <b>需求：</b>有一个生产者线程负责生产产品，一个消费者线程负责消费产品。<br />
 * <b>要求：</b>确保生产者不会在队列满时继续生产，消费者不会在队列空时继续消费。
 * </p>
 *
 * @author zhangrongkang
 * @since 2023/10/12
 */
public class ModelPractice {

    /**
     * 生产者模型
     */
    static class Producer implements Runnable {

        /**
         * 工作队列
         */
        private final ArrayBlockingQueue<Integer> workQueue;

        public Producer(ArrayBlockingQueue<Integer> workQueue) {
            this.workQueue = workQueue;
        }

        /**
         * 生产者用于生产数据，同时将数据存储到工作队列中
         * 如果工作队列已满，则进入等待状态，直到工作队列中有容量后将其唤醒
         */
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                try {
                    // 将产品放入队列
                    workQueue.put(i);
                    System.out.println(Thread.currentThread().getName() + " Producing: " + i + " 剩余容量：" + workQueue.remainingCapacity());
                    // 线程休息50ms模拟生产过程
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    // 中断线程
                    Thread.currentThread().interrupt();
                }
            }

        }
    }

    /**
     * 消费者模型
     */
    static class Consumer implements Runnable {
        /**
         * 工作队列
         */
        private final ArrayBlockingQueue<Integer> workQueue;

        public Consumer(ArrayBlockingQueue<Integer> workQueue) {
            this.workQueue = workQueue;
        }

        @Override
        public void run() {
            try {
                for (int i = 0; i < 100; i++) {
                    // 从队列中取出产品
                    Integer item = workQueue.take();
                    System.out.println(Thread.currentThread().getName() + " Consuming: ---------------- " + item + " ---------------- " + "元素个数：" + workQueue.size());
                    // 线程休息100ms模拟消费过程
                    Thread.sleep(100);
                }
            } catch (InterruptedException e) {
                // 中断线程
                Thread.currentThread().interrupt();
            }
        }

    }

    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName() + "： ");
        // 创建一个容量为10的工作队列
        ArrayBlockingQueue<Integer> workQueue = new ArrayBlockingQueue<>(10);

        // 创建生产者和消费者线程
        Thread producer = new Thread(new Producer(workQueue));
        producer.start();

        Thread consumer = new Thread(new Consumer(workQueue));
        consumer.start();

        try {
            // 等待生产者线程执行完成
            producer.join();
            // 等待消费者线程执行完成
            consumer.join();
        } catch (InterruptedException e) {
            // 中断线程
            Thread.currentThread().interrupt();
        }

        System.out.println("All threads have completed. Exiting.");
    }
}
